// ///////////////////////////// MIT License //////////////////////////////////// //
//                                                                                //
// Copyright (c) 2010 David Zsolt Manrique                                        //
//                    david.zsolt.manrique@gmail.com                              //
//                                                                                //
// Permission is hereby granted, free of charge, to any person obtaining a copy   //
// of this software and associated documentation files (the "Software"), to deal  //
// in the Software without restriction, including without limitation the rights   //
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell      //
// copies of the Software, and to permit persons to whom the Software is          //
// furnished to do so, subject to the following conditions:                       //
//                                                                                //
// The above copyright notice and this permission notice shall be included in     //
// all copies or substantial portions of the Software.                            //
//                                                                                //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR     //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,       //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE    //
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER         //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  //
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN      //
// THE SOFTWARE.                                                                  //
//                                                                                //
// ////////////////////////////////////////////////////////////////////////////// //


#include <iostream>
#include <ostream>
#include <sstream>
#include <vector>
#include <algorithm>
#include <complex>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <list>
#include <set>
#include <cstdarg>
#include <stdexcept>

#include <sys/stat.h>

#include <cmdioutil.h>
#include "xyz.h"

#include <X11/Xlib.h>
#include <stdio.h>
#include <X11/Xutil.h>
#include <sys/time.h>
//#include <signal.h>


using namespace std;

#define TRUE 1
#define FALSE 0
/*
namespace graphic_context
{
	bond[3];
	atom[5];
	measure_line[2];
	axis[6];
	label[3];
	void init(Display & display, Window & window)
	{
		;
	}
}
*/


// this is my first program with X, so conceptual mistakes are guaranteed
// it was intended to test how X works, but the program turned to be very useful
// so if you would like to write this program in organized way please tell me and go ahead!!!
struct atomview
{
	std::map<std::string,double> radius;
	std::map<std::string,int> color; 
	
	atomview()
	{
		radius["H"] = 0.75; radius["He"] = 0;	
	
		radius["Li"] = 1.45; radius["Be"] = 1.05;  radius["B"] = 0.85;  radius["C"] = 0.70;  radius["N"] = 0.65; radius["O"] = 0.60; radius["F"] = 0.50;  radius["Ne"] = 0;
		radius["Na"]  = 1.80; radius["Mg"] = 1.50; radius["Al"] = 1.25; radius["Si"] = 1.10; radius["P"] = 1.00; radius["S"] = 1.00; radius["Cl"] = 1.00; radius["Ar"] = 0;
	
		radius["K"] = 2.20;  radius["Ca"] = 1.80;  radius["Sc"] = 1.60; radius["Ti"] = 1.40; radius["V"] = 1.35;   radius["Cr"] = 1.40; radius["Mn"] = 1.40; radius["Fe"] = 1.40;
		radius["Co"] = 1.35; radius["Ni"] = 1.35;  radius["Cu"] = 1.35; radius["Zn"] = 1.35; radius["Ga"] = 1.30;  radius["Ge"] = 1.25; radius["As"] = 1.15; radius["Se"] = 1.15;
		radius["Br"] = 1.15; radius["Kr"] = 0;
	
		radius["Rb"] = 2.35; radius["Sr"] = 2.00;  radius["Y"] = 1.80;  radius["Zr"] = 1.55; radius["Nb"] = 1.45; radius["Mo"] = 1.45; radius["Tc"] = 1.35; radius["Ru"] = 1.30;
		radius["Rh"] = 1.35; radius["Pd"] = 1.40;  radius["Ag"] = 1.60; radius["Cd"] = 1.55; radius["In"] = 1.55; radius["Sn"] = 1.45; radius["Sb"] = 1.45; radius["Te"] = 1.40;
		radius["I"] = 1.40;  radius["Xe"] = 0;
		
		radius["Cs"] = 2.60; radius["Ba"] = 2.15;  radius["*"] = 0;     radius["Hf"] = 1.55; radius["Ta"] = 1.45; radius["W"] = 1.35;  radius["Re"] = 1.35; radius["Os"] = 1.30;
		radius["Ir"] = 1.35; radius["Pt"] = 1.35;  radius["Au"] = 1.35; radius["Hg"] = 1.50; radius["Tl"] = 1.90; radius["Pb"] = 1.80; radius["Bi"] = 1.60; radius["Po"] = 1.90;
		radius["At"] = 0;    radius["Rn"] = 0;
	
		radius["Fr"] = 0;    radius["Ra"] = 2.15;  radius["**"] = 0;    radius["Rf"] = 0;    radius["Db"] = 0;    radius["Sg"] = 0;    radius["Bh"] = 0;    radius["Hs"] = 0;
		radius["Mt"] = 0;    radius["Ds"] = 0;     radius["Rg"] = 0;    radius["Uub"] = 0;   radius["Uut"] = 0;   radius["Uuq"] = 0;   radius["Uup"] = 0;   radius["Uuh"] = 0;
		radius["Uus"] = 0;   radius["Uuo"] = 0;
	
		radius["La"] = 1.95; radius["Ce"] = 1.85;  radius["Pr"] = 1.85; radius["Nd"] = 1.85; radius["Pm"] = 1.85; radius["Sm"] = 1.85; radius["Eu"] = 1.85; radius["Gd"] = 1.80;	
		radius["Tb"] = 1.75; radius["Dy"] = 1.75;  radius["Ho"] = 1.75; radius["Er"] = 1.75; radius["Tm"] = 1.75; radius["Yb"] = 1.75; radius["Lu"] = 1.75;
	
		radius["Ac"] = 1.95; radius["Th"] = 1.80; radius["Pa"] = 1.80; radius["U"] = 1.75; radius["Np"] = 1.75; radius["Pu"] = 1.75; radius["Am"] = 1.75; radius["Cm"] = 0;
		radius["Bk"] = 0;    radius["Cf"] = 0;    radius["Es"] = 0;    radius["Fm"] = 0;   radius["Md"] = 0;    radius["No"] = 0;    radius["Lr"] = 0;
	}

};


struct xyzview : xyz
{
  	atomview av;
	std::string frame_label;

	int width,height;
	int ox,oy; int r; double dist;
	xyzview() : ox(250), oy(250), r(30), dist(0.65) {}

	// //
	Eigen::Transform<double,3,Eigen::Affine> t,rot,tra;
	std::vector<Eigen::Vector3d> rotated_coords;
	std::vector<int> coordX;
	std::vector<int> coordY;
	// //

	int getX(Eigen::Vector3d & p) { return static_cast<int>(r* p.x() + ox); }
	int getY(Eigen::Vector3d & p) { return static_cast<int>(r* p.y() + oy); }


        // edit mode //
        bool is_edit_mode;
        // end edit mode //	

        // edit transform //
	void edit_translate_x(double d) { for(int i = 0; i<n; i++)  if(selected_atom[i]) coords[i].x() += d; }
	void edit_translate_y(double d) { for(int i = 0; i<n; i++)  if(selected_atom[i]) coords[i].y() += d; }
	void edit_translate_z(double d) { for(int i = 0; i<n; i++)  if(selected_atom[i]) coords[i].z() += d; }
        
        // end edit transform //
	
	// edit transform //
	void edit_send_away() { for(int i = 0; i<n; i++)  if(selected_atom[i]) coords[i].z() += 10000.0; }
	// end edit transform //



	// view transform //
	bool did_view_transformed;
	void transform() 
	{ 
		if(!did_view_transformed) for(int i = 0; i < n; i++) 
		{ 
			did_view_transformed = true; 
			rotated_coords[i] = t*coords[i]; 
			coordX[i] = getX(rotated_coords[i]);
			coordY[i] = getY(rotated_coords[i]);
		} 
	}
	// end view transform //


	// select //
	int draw_selatom_type;
	void set_draw_selatom_type() { draw_selatom_type = (draw_selatom_type+1) % 4;  }
	std::vector<short> selected_atom;
	GC gc_selatom1,gc_selatom2;	
	int find(int px,int py)
	{
		int d = r*r/4;
		int index = -1;
		for(int i = 0; i<n; i++) if( (coordX[i]-px)*(coordX[i]-px) + (coordY[i]-py)*(coordY[i]-py) < d ) 
		{
		   index = i;
		   d = (coordX[i]-px)*(coordX[i]-px) + (coordY[i]-py)*(coordY[i]-py);
		}
		return index;
	}
	void select_atom(int px,int py)
	{	
		int i = find(px,py);
		if(i>=0) selected_atom[i] = 1;
		//std::cerr << i << std::endl;
	}
	void deselect_atom(int px,int py)
	{	
		int i = find(px,py);
		if(i>=0)selected_atom[i] = 0;
	}
	void deselect_allatom()
	{	
		for(int i = 0; i < n; i++) selected_atom[i] = 0;
	}	
	void init_draw_selatom(Display * display, Window & windows)
	{
		gc_selatom1 = XCreateGC(display, windows, 0, 0);
		set_color(display,"#FF00CC",gc_selatom1);
		XSetLineAttributes(display, gc_selatom1, 1, 0, 0, 0);	

		gc_selatom2 = XCreateGC(display, windows, 0, 0);
		set_color(display,"#FF00CC",gc_selatom2);		
		XSetLineAttributes(display, gc_selatom2, 2, 0, 0, 0);	
	}
	void draw_selatom(Display * display, Window & windows)
	{
		switch(draw_selatom_type)
		{
			case 0:
			break;
			case 1:	  
			transform();
			for(int i = 0; i < n; i++)
			if(selected_atom[i] == 1) XDrawArc(display,windows,gc_selatom1,coordX[i]-2,coordY[i]-2,4,4,0,23040);
			break;
			case 2:	  
			transform();
			for(int i = 0; i < n; i++)
			if(selected_atom[i] == 1) XDrawArc(display,windows,gc_selatom2,coordX[i]-4,coordY[i]-4,8,8,0,23040);
			for(int i = 0; i<bond_topology.size(); i++)
			if((selected_atom[bond_topology[i].first] == 1)&&(selected_atom[bond_topology[i].second] == 1))
			{
				Eigen::Vector3d &ci = rotated_coords[bond_topology[i].first];
				Eigen::Vector3d &cj = rotated_coords[bond_topology[i].second];

				XDrawLine(display,windows,gc_selatom2,static_cast<int>(r* ci.x() + ox),static_cast<int>(r* ci.y() + oy),static_cast<int>(r* cj.x() + ox),static_cast<int>(r* cj.y() + oy));
			  
			}			
			break;
			case 3:	  
			transform();
			for(int i = 0; i < n; i++)
			if(selected_atom[i] == 1)
			{
				std::string lab; util::to(i+1,lab); lab = labels[i]+lab;
				XDrawString(display,windows,gc_selatom2,coordX[i]-2,coordY[i]-2, lab.c_str(), lab.length());
			}
			break;
			default: ;
		}
	}
	// end select //	


	// transformation //
	void rotatex(double angle) { rot = Eigen::AngleAxisd(angle, Eigen::Vector3d::UnitX())*rot; did_view_transformed = false; }
	void rotatey(double angle) { rot = Eigen::AngleAxisd(angle, Eigen::Vector3d::UnitY())*rot; did_view_transformed = false; }
	void setanglex(double angle) { rot = Eigen::AngleAxisd(angle, Eigen::Vector3d::UnitX()); did_view_transformed = false; }	
	void setangley(double angle) { rot = Eigen::AngleAxisd(angle, Eigen::Vector3d::UnitY())*Eigen::AngleAxisd(-angle, Eigen::Vector3d::UnitZ()); did_view_transformed = false; }	
	void setanglez(double angle) { rot = Eigen::AngleAxisd(angle, Eigen::Vector3d::UnitZ()); did_view_transformed = false; }
	void translatex(int dpx) { ox += dpx; did_view_transformed = false; }
	void translatey(int dpy) { oy += dpy; did_view_transformed = false; }
	void scale(int dr) { if( r+dr > 0 ) r += dr; did_view_transformed = false; }
	// end transformation //

	// Graphic contex //
	void set_color(Display * display,const char* rgb, GC & gc)
	{
		XColor color;
		Colormap colormap = DefaultColormap(display, 0);  
		XParseColor(display, colormap, rgb, &color);
		XAllocColor(display, colormap, &color);
		XSetForeground(display, gc, color.pixel);
	}
	// end GC //
	
	
	// axis //
	int draw_axis_type;
	void set_draw_axis_type() { draw_axis_type = (draw_axis_type+1) % 3;  }
	double xaxis_length,yaxis_length,zaxis_length;
	void set_axis_length() { xaxis_length = 5.0; yaxis_length = 5.0; zaxis_length = 5.0; }
	GC gc_xaxis1, gc_yaxis1, gc_zaxis1,gc_xaxis2, gc_yaxis2, gc_zaxis2;
	void init_draw_axis(Display * display, Window & windows)
	{
		XGCValues values;
		XFontStruct *font;
		font = XLoadQueryFont(display, "-*-fixed-*-15-*");
		//font = XLoadQueryFont(display, "-*-helvetica-*-15-*");
		if (!font) { std::cerr << "Warning: unable to load preferred font " << "-*-helvetica-*-10-*" << std::endl; font = XLoadQueryFont(display, "fixed"); }
		values.font = font->fid;

	  
		char red[] = "#FF0000"; char green[] = "#00FF00"; char blue[] = "#0000FF";
		
		gc_xaxis1 = XCreateGC(display, windows, 0, 0);
		set_color(display,red,gc_xaxis1);
		XSetLineAttributes(display, gc_xaxis1, 1, 0, 0, 0);
		
		gc_yaxis1 = XCreateGC(display, windows, 0, 0);
		set_color(display,green,gc_yaxis1);
		XSetLineAttributes(display, gc_yaxis1, 1, 0, 0, 0);	
		
		gc_zaxis1 = XCreateGC(display, windows, 0, 0);
		set_color(display,blue,gc_zaxis1);
		XSetLineAttributes(display, gc_zaxis1, 1, 0, 0, 0);	
		
		gc_xaxis2 = XCreateGC(display, windows,  GCFont,&values);
		set_color(display,red,gc_xaxis2);
		XSetLineAttributes(display, gc_xaxis2, 2, 0, 0, 0);
		
		gc_yaxis2 = XCreateGC(display, windows,  GCFont,&values);
		set_color(display,green,gc_yaxis2);
		XSetLineAttributes(display, gc_yaxis2, 2, 0, 0, 0);	
		
		gc_zaxis2 = XCreateGC(display, windows,  GCFont,&values);
		set_color(display,blue,gc_zaxis2);
		XSetLineAttributes(display, gc_zaxis2, 2, 0, 0, 0);	
	}
	void draw_axis(Display * display, Window & windows)
	{
		Eigen::Vector3d xaxis ;
		Eigen::Vector3d yaxis ;
		Eigen::Vector3d zaxis ;
		Eigen::Vector3d mxaxis ;
		Eigen::Vector3d myaxis ;
		Eigen::Vector3d mzaxis ;		
		Eigen::Vector3d origin;
		switch(draw_axis_type)
		{
			case 0:
			break;
			case 1:
			xaxis = t*Eigen::Vector3d(xaxis_length,0,0);
			yaxis = t*Eigen::Vector3d(0,yaxis_length,0);
			zaxis = t*Eigen::Vector3d(0,0,zaxis_length);			
			mxaxis = t*Eigen::Vector3d(-1,0,0);
			myaxis = t*Eigen::Vector3d(0,-1,0);
			mzaxis = t*Eigen::Vector3d(0,0,-1);
			
			XDrawLine(display,windows,gc_xaxis1,static_cast<int>(r* mxaxis.x() + ox),static_cast<int>(r* mxaxis.y() + oy),static_cast<int>(r* xaxis.x() + ox),static_cast<int>(r* xaxis.y() + oy));
			XDrawLine(display,windows,gc_yaxis1,static_cast<int>(r*  myaxis.x() + ox),static_cast<int>(r* myaxis.y() + oy),static_cast<int>(r* yaxis.x() + ox),static_cast<int>(r* yaxis.y() + oy));
			XDrawLine(display,windows,gc_zaxis1,static_cast<int>(r*  mzaxis.x() + ox),static_cast<int>(r* mzaxis.y() + oy),static_cast<int>(r* zaxis.x() + ox),static_cast<int>(r* zaxis.y() + oy));
			break;
			case 2:
			xaxis = t*Eigen::Vector3d(2*xaxis_length,0,0);
			yaxis = t*Eigen::Vector3d(0,2*yaxis_length,0);
			zaxis = t*Eigen::Vector3d(0,0,2*zaxis_length);			
			mxaxis = t*Eigen::Vector3d(-2,0,0);
			myaxis = t*Eigen::Vector3d(0,-2,0);
			mzaxis = t*Eigen::Vector3d(0,0,-2);
			
			XDrawLine(display,windows,gc_xaxis2,static_cast<int>(r* mxaxis.x() + ox),static_cast<int>(r* mxaxis.y() + oy),static_cast<int>(r* xaxis.x() + ox),static_cast<int>(r* xaxis.y() + oy));
			XDrawLine(display,windows,gc_yaxis2,static_cast<int>(r*  myaxis.x() + ox),static_cast<int>(r* myaxis.y() + oy),static_cast<int>(r* yaxis.x() + ox),static_cast<int>(r* yaxis.y() + oy));
			XDrawLine(display,windows,gc_zaxis2,static_cast<int>(r*  mzaxis.x() + ox),static_cast<int>(r* mzaxis.y() + oy),static_cast<int>(r* zaxis.x() + ox),static_cast<int>(r* zaxis.y() + oy));

			XDrawString(display,windows,gc_xaxis2,static_cast<int>(r* xaxis.x() + ox+5),static_cast<int>(r* xaxis.y() + oy),"X", 1);
			XDrawString(display,windows,gc_yaxis2,static_cast<int>(r* yaxis.x() + ox+5),static_cast<int>(r* yaxis.y() + oy),"Y", 1);
			XDrawString(display,windows,gc_zaxis2,static_cast<int>(r* zaxis.x() + ox+5),static_cast<int>(r* zaxis.y() + oy),"Z", 1);
			break;
			default: ;
		}
	  
	}
	// end axis //
	
	
	// bonds //
	int draw_bond_type;
	void set_draw_bond_type() { draw_bond_type = (draw_bond_type+1) % 3;  }
	GC gc_bond1,gc_bond2;
	void init_draw_bond(Display * display, Window & windows)
	{
		char white1[] = "#3F3F3F";
		gc_bond1 = XCreateGC(display, windows, 0, 0);
		set_color(display,white1,gc_bond1);
		XSetLineAttributes(display, gc_bond1, 1, 1, 0, 0);
		
		char white2[] = "#33CCCC";
		gc_bond2 = XCreateGC(display, windows, 0, 0);
		set_color(display,white2,gc_bond2);
		XSetLineAttributes(display, gc_bond2, 1, 0, 0, 0);		
	}
	void draw_bond(Display * display, Window & windows)
	{
		switch(draw_bond_type)
		{
			case 0:
			break;
			case 1:
			transform();
			for(int i = 0; i<bond_topology.size(); i++)
			{
				Eigen::Vector3d &ci = rotated_coords[bond_topology[i].first];
				Eigen::Vector3d &cj = rotated_coords[bond_topology[i].second];
			
				//if( (ci-cj).norm() < av.radius[labels[i]]+av.radius[labels[j]] + dist )
				XDrawLine(display,windows,gc_bond1,static_cast<int>(r* ci.x() + ox),static_cast<int>(r* ci.y() + oy),static_cast<int>(r* cj.x() + ox),static_cast<int>(r* cj.y() + oy));
			}
			break;
			case 2:
			transform();
			for(int i = 0; i<bond_topology.size(); i++)
			{
				Eigen::Vector3d &ci = rotated_coords[bond_topology[i].first];
				Eigen::Vector3d &cj = rotated_coords[bond_topology[i].second];
			
				//if( (ci-cj).norm() < av.radius[labels[i]]+av.radius[labels[j]] + dist )
				XDrawLine(display,windows,gc_bond2,static_cast<int>(r* ci.x() + ox),static_cast<int>(r* ci.y() + oy),static_cast<int>(r* cj.x() + ox),static_cast<int>(r* cj.y() + oy));
			  
			}
			break;
			default: ;
		}
		
	}
	// end bonds //	
	
	// atom //
	int draw_atom_type;
	void set_draw_atom_type() { draw_atom_type = (draw_atom_type+1) % 3;  }
	GC gc_atom1,gc_atom2;
	void init_draw_atom(Display * display, Window & windows)
	{
		gc_atom1 = XCreateGC(display, windows, 0, 0);
		set_color(display,"#2F4F4F",gc_atom1);

		gc_atom2 = XCreateGC(display, windows, 0, 0);
		set_color(display,"#FF7F00",gc_atom2);		
	}
	void draw_atom(Display * display, Window & windows)
	{
		switch(draw_atom_type)
		{
			case 0:
			break;
			case 1:	  
			transform();
			for(int i = 0; i < n; i++)
			{	
				Eigen::Vector3d &ci = rotated_coords[i];
				XFillArc(display,windows,gc_atom1,static_cast<int>(r* ci.x() + ox - 2),static_cast<int>(r* ci.y() + oy - 2),4,4,0,23040);
			}	
			break;
			case 2:	  
			transform();
			for(int i = 0; i < n; i++)
			{	
				Eigen::Vector3d &ci = rotated_coords[i];
				XFillArc(display,windows,gc_atom2,static_cast<int>(r* ci.x() + ox - 4),static_cast<int>(r* ci.y() + oy - 4),8,8,0,23040);
			}	
			break;
			default: ;
		}
	}
	// end atom //	

	// label //
	int draw_label_type;
	void set_draw_label_type() { draw_label_type = (draw_label_type+1) % 5;  }
	GC gc_label1,gc_label2;
	void init_draw_label(Display * display, Window & windows)
	{
		XGCValues values;
		XFontStruct *font;
		font = XLoadQueryFont(display, "-*-fixed-*-15-*");
		//font = XLoadQueryFont(display, "-*-helvetica-*-15-*");
		if (!font) { std::cerr << "Warning: unable to load preferred font " << "-*-helvetica-*-10-*" << std::endl; font = XLoadQueryFont(display, "fixed"); }
		values.font = font->fid;
		
		
		gc_label1 = XCreateGC(display, windows,0,0);
		set_color(display,"#FFFFFF",gc_label1);

		gc_label2 = XCreateGC(display, windows ,GCFont,&values);
		set_color(display,"#00FF22",gc_label2);		
	}
	void draw_label(Display * display, Window & windows)
	{
		switch(draw_label_type)
		{
			case 0:
			break;
			case 1:	  
			transform();
			for(int i = 0; i < n; i++)
			{	
				Eigen::Vector3d &ci = rotated_coords[i];
				std::string lab;
				util::to(i+1,lab);
				lab = labels[i]+lab;
				XDrawString(display,windows,gc_label1,static_cast<int>(r* ci.x() + ox - 2),static_cast<int>(r* ci.y() + oy - 2), lab.c_str(), lab.length());
			}	
			break;
			case 2:	  
			transform();
			for(int i = 0; i < n; i++)
			if( (draw_selatom_type == 0) || (selected_atom[i] == 0))
			{	
				Eigen::Vector3d &ci = rotated_coords[i];
				XDrawString(display,windows,gc_label2,static_cast<int>(r* ci.x() + ox - 2),static_cast<int>(r* ci.y() + oy - 2), labels[i].c_str(), labels[i].length());
			}	
			break;
			case 3:	  
			transform();
			for(int i = 0; i < n; i++)
			if( (draw_selatom_type == 0) || (selected_atom[i] == 0))
			{	
				Eigen::Vector3d &ci = rotated_coords[i];
				std::string lab;
				util::to(i+1,lab);
				XDrawString(display,windows,gc_label2,static_cast<int>(r* ci.x() + ox - 2),static_cast<int>(r* ci.y() + oy - 2), lab.c_str(), lab.length());
			}	
			break;
			case 4:	  
			transform();
			for(int i = 0; i < n; i++)
			if( (draw_selatom_type == 0) || (selected_atom[i] == 0))
			{	
				Eigen::Vector3d &ci = rotated_coords[i];
				std::string lab;
				util::to<int,std::string>(i-int(n),lab);
				XDrawString(display,windows,gc_label2,static_cast<int>(r* ci.x() + ox - 2),static_cast<int>(r* ci.y() + oy - 2), lab.c_str(), lab.length());
			}	
			break;
			default: ;
		}
	}
	// end label //	

	// measure //
	int draw_measure_type;
	void set_draw_measure_type() { draw_measure_type = (draw_measure_type+1) % 3;  }
	GC gc_measure,gc_measure_line;
	void init_draw_measure(Display * display, Window & windows)
	{
//		XGCValues values;
//		XFontStruct *font;
//		font = XLoadQueryFont(display, "-*-fixed-*-15-*");
		//font = XLoadQueryFont(display, "-*-helvetica-*-15-*");
//		if (!font) { std::cerr << "Warning: unable to load preferred font " << "-*-helvetica-*-10-*" << std::endl; font = XLoadQueryFont(display, "fixed"); }
//		values.font = font->fid;

		gc_measure_line = XCreateGC(display, windows, 0, 0);
		set_color(display,"#3F3F3F",gc_measure_line);
		XSetLineAttributes(display,gc_measure_line, 1, 1, 0, 0);
		
		gc_measure = XCreateGC(display, windows,0,0);
		set_color(display,"#FFFFFF",gc_measure);

	}
	std::set<std::pair<int,int> > connections;
	int connecting_atom;;
	int find_atom(int px,int py)
	{
		int d = r*r/4;
		int index = -1;
		for(int i = 0; i<n; i++) if( (coordX[i]-px)*(coordX[i]-px) + (coordY[i]-py)*(coordY[i]-py) < d ) 
		{
		   index = i;
		   d = (coordX[i]-px)*(coordX[i]-px) + (coordY[i]-py)*(coordY[i]-py);
		}
		return index;
	}
	void connect_atom(int px,int py)
	{	
	    if(connecting_atom==-1)
	    {
		connecting_atom = find_atom(px,py);
	    }
	    else
	    {
	        int current_atom = find_atom(px,py);
	        if(current_atom >= 0 && connecting_atom != current_atom)
	        {
        	    std::set<std::pair<int,int> >::iterator it;
    	            it = connections.find(std::pair<int,int>(connecting_atom,current_atom));
	            if(it == connections.end()) it = connections.find(std::pair<int,int>(current_atom,connecting_atom));
	            if(it != connections.end()) connections.erase(*it);
	            else  connections.insert(std::pair<int,int>(connecting_atom,current_atom));
	        }
	        connecting_atom = current_atom;
	        
	    }
	}
	void draw_measure(Display * display, Window & windows)
	{
		switch(draw_measure_type)
		{
			case 0:
//			for(int i = 0; i<measure_pairs.size(); i++)
			for(std::set<std::pair<int,int> >::iterator it = connections.begin(); it != connections.end(); it++)
			{
				Eigen::Vector3d &ci = rotated_coords[it->first];
				Eigen::Vector3d &cj = rotated_coords[it->second];
				std::string lab;
				std::ostringstream oss;
				oss << std::setprecision(3) << (ci-cj).norm();
				lab = oss.str();
			        Eigen::Vector3d dij = 0.5*(ci+cj);
				XDrawLine(display,windows,gc_measure_line,static_cast<int>(r* ci.x() + ox),static_cast<int>(r* ci.y() + oy),static_cast<int>(r* cj.x() + ox),static_cast<int>(r* cj.y() + oy));
				XDrawString(display,windows,gc_measure,static_cast<int>(r* dij.x() + ox - 2),static_cast<int>(r* dij.y() + oy - 2), lab.c_str(), lab.length());
			}
			break;
			case 1:	  
			transform();
			for(int i = 0; i<bond_topology.size(); i++)
			{
				Eigen::Vector3d &ci = rotated_coords[bond_topology[i].first];
				Eigen::Vector3d &cj = rotated_coords[bond_topology[i].second];
				std::string lab;
				std::ostringstream oss;
				oss << std::setprecision(3) << (ci-cj).norm();
				lab = oss.str();
			        Eigen::Vector3d dij = 0.5*(ci+cj);
				//XDrawLine(display,windows,gc_measure_line,static_cast<int>(r* ci.x() + ox),static_cast<int>(r* ci.y() + oy),static_cast<int>(r* cj.x() + ox),static_cast<int>(r* cj.y() + oy));
				XDrawString(display,windows,gc_measure,static_cast<int>(r* dij.x() + ox - 2),static_cast<int>(r* dij.y() + oy - 2), lab.c_str(), lab.length());
			}
			break;
			case 2:	  
			transform();
			for(int i = 0; i<bond_topology.size(); i++)
			if( (selected_atom[bond_topology[i].first] == 1) && (selected_atom[bond_topology[i].second] == 1))
			{
				Eigen::Vector3d &ci = rotated_coords[bond_topology[i].first];
				Eigen::Vector3d &cj = rotated_coords[bond_topology[i].second];
				std::string lab;
				std::ostringstream oss;
				oss << std::setprecision(3) << (ci-cj).norm();
				lab = oss.str();
			        Eigen::Vector3d dij = 0.5*(ci+cj);
				//XDrawLine(display,windows,gc_measure_line,static_cast<int>(r* ci.x() + ox),static_cast<int>(r* ci.y() + oy),static_cast<int>(r* cj.x() + ox),static_cast<int>(r* cj.y() + oy));
				XDrawString(display,windows,gc_measure,static_cast<int>(r* dij.x() + ox - 2),static_cast<int>(r* dij.y() + oy - 2), lab.c_str(), lab.length());
			}
			break;
//			case 2:	  
//			transform();
//			for(int i = 0; i < n; i++)
//			if( (draw_selatom_type == 0) || (selected_atom[i] == 0))
//			{	
//				Eigen::Vector3d &ci = rotated_coords[i];
//				XDrawString(display,windows,gc_label2,static_cast<int>(r* ci.x() + ox - 2),static_cast<int>(r* ci.y() + oy - 2), labels[i].c_str(), labels[i].length());
//			}	
//			break;
			default: ;
		}
	}
	// end measure //	


	// help //
	int draw_help_type;
	void set_draw_help_type() { draw_help_type = (draw_help_type+1) % 3;  }
	GC gc_help1,gc_help2,gc_help_frame_label;
	void init_draw_help(Display * display, Window & windows)
	{
		XGCValues values;
		XFontStruct *font;
		font = XLoadQueryFont(display, "-*-fixed-*-15-*");
		//font = XLoadQueryFont(display, "-*-helvetica-*-15-*");
		if (!font) { std::cerr << "Warning: unable to load preferred font " << "-*-helvetica-*-10-*" << std::endl; font = XLoadQueryFont(display, "fixed"); }
		
		values.font = font->fid;
		gc_help1 = XCreateGC(display, windows, GCFont,&values);
		set_color(display,"#CCCCCC",gc_help1);

		gc_help2 = XCreateGC(display, windows,  GCFont,&values);
		set_color(display,"#555555",gc_help2);		

		gc_help_frame_label = XCreateGC(display, windows,  GCFont,&values);
		set_color(display,"#FF4040",gc_help_frame_label);		

	}
	void draw_help(Display * display, Window & windows)
	{
		switch(draw_help_type)
		{
			case 0:
			break;
			case 1:	  
			{
				std::string help;
				//help = "q:quit   h:help   a:atom   b:help   c:axis  l:label  u:unit cell o:center  s:show selected  xyz:views  1234: defaults";
				if(!is_edit_mode)
				{
				help = "h:help  q:quit"; XDrawString(display,windows,gc_help1,3,15, help.c_str(), help.length());
				help = "a:atom";         XDrawString(display,windows,gc_help1,3,30, help.c_str(), help.length());
				help = "b:bond";         XDrawString(display,windows,gc_help1,3,45, help.c_str(), help.length());
				help = "c:axis";         XDrawString(display,windows,gc_help1,3,60, help.c_str(), help.length());
				help = "l:label";        XDrawString(display,windows,gc_help1,3,75, help.c_str(), help.length());
				help = "u:unitcell";     XDrawString(display,windows,gc_help1,3,90, help.c_str(), help.length());
				help = "o:center";       XDrawString(display,windows,gc_help1,3,105, help.c_str(), help.length());
				help = "s:selected";     XDrawString(display,windows,gc_help1,3,120, help.c_str(), help.length());
				help = "m:measure";      XDrawString(display,windows,gc_help1,3,135, help.c_str(), help.length());
				help = "xyz:views";      XDrawString(display,windows,gc_help1,3,150, help.c_str(), help.length());
				help = "r:reload";       XDrawString(display,windows,gc_help1,3,165, help.c_str(), help.length());
				help = "e:edit";         XDrawString(display,windows,gc_help1,3,180, help.c_str(), help.length());
				
				                         XDrawString(display,windows,gc_xaxis2,5,195, "X", 1);
				                         XDrawString(display,windows,gc_yaxis2,15,195, "Y", 1);
				                         XDrawString(display,windows,gc_zaxis2,25,195, "Z", 1);
				                         XDrawString(display,windows,gc_a1ucbox2,60,195, "A1", 2);
				                         XDrawString(display,windows,gc_a2ucbox2,80,195, "A2", 2);
				                         XDrawString(display,windows,gc_a3ucbox2,100,195, "A3", 2);

				help = "FRAME : "+frame_label; XDrawString(display,windows,gc_help_frame_label,3,213, help.c_str(), help.length());
				help = "Home PgUp PgDown End"; XDrawString(display,windows,gc_help_frame_label,3,231, help.c_str(), help.length());
				help = comment;                XDrawString(display,windows,gc_help1,3,246, help.c_str(), help.length());
				}
				else
				{
				
				help = "EDIT MODE";      XDrawString(display,windows,gc_help2,3,30, help.c_str(), help.length());
				help = "u:+x   h:-x";    XDrawString(display,windows,gc_help1,3,45, help.c_str(), help.length());
				help = "i:+y   j:-y";    XDrawString(display,windows,gc_help1,3,60, help.c_str(), help.length());
				help = "o:+z   k:-z";    XDrawString(display,windows,gc_help1,3,75, help.c_str(), help.length());
				help = "";        XDrawString(display,windows,gc_help1,3,90, help.c_str(), help.length());
				help = "";     XDrawString(display,windows,gc_help1,3,105, help.c_str(), help.length());
				help = "d:del frame";       XDrawString(display,windows,gc_help1,3,120, help.c_str(), help.length());
				help = "a:ins frame";     XDrawString(display,windows,gc_help1,3,135, help.c_str(), help.length());
				help = "w:write frame";      XDrawString(display,windows,gc_help1,3,150, help.c_str(), help.length());
				help = "v:view";         XDrawString(display,windows,gc_help1,3,165, help.c_str(), help.length());

				                         XDrawString(display,windows,gc_xaxis2,5,180, "X", 1);
				                         XDrawString(display,windows,gc_yaxis2,15,180, "Y", 1);
				                         XDrawString(display,windows,gc_zaxis2,25,180, "Z", 1);
				                         XDrawString(display,windows,gc_a1ucbox2,60,180, "A1", 2);
				                         XDrawString(display,windows,gc_a2ucbox2,80,180, "A2", 2);
				                         XDrawString(display,windows,gc_a3ucbox2,100,180, "A3", 2);

				help = "FRAME : "+frame_label; XDrawString(display,windows,gc_help_frame_label,3,198, help.c_str(), help.length());

				}
			}	
			break;
			case 2:	 
			{
				std::string help;
				help = "q h a b c l u o s m x y z e r 1 2 3 4";
				XDrawString(display,windows,gc_help2,3,13, help.c_str(), help.length());
				help = "FRAME : "+frame_label; XDrawString(display,windows,gc_help_frame_label,3,28, help.c_str(), help.length());
			}
			break;
			default: ;
		}
	}
	// end help //	
	


	// ucbox //
	int draw_ucbox_type;
	void set_draw_ucbox_type() { draw_ucbox_type = (draw_ucbox_type+1) % 3;  }
	GC gc_a1ucbox1, gc_a2ucbox1, gc_a3ucbox1,gc_a1ucbox2, gc_a2ucbox2, gc_a3ucbox2;
	void init_draw_ucbox(Display * display, Window & windows)
	{
		XGCValues values;
		XFontStruct *font;
		font = XLoadQueryFont(display, "-*-fixed-*-15-*");
		//font = XLoadQueryFont(display, "-*-helvetica-*-15-*");
		if (!font) { std::cerr << "Warning: unable to load preferred font " << "-*-helvetica-*-10-*" << std::endl; font = XLoadQueryFont(display, "fixed"); }
		values.font = font->fid;

	  
		char red[] = "#FF33CC";
		char green[] = "#CCFF33";
		char blue[] = "#33CCFF";
		
		gc_a1ucbox1 = XCreateGC(display, windows, 0, 0);
		set_color(display,red,gc_a1ucbox1);
		XSetLineAttributes(display, gc_a1ucbox1, 1, 1, 0, 0);
		
		gc_a2ucbox1 = XCreateGC(display, windows, 0, 0);
		set_color(display,green,gc_a2ucbox1);
		XSetLineAttributes(display, gc_a2ucbox1, 1, 1, 0, 0);	
		
		gc_a3ucbox1 = XCreateGC(display, windows, 0, 0);
		set_color(display,blue,gc_a3ucbox1);
		XSetLineAttributes(display, gc_a3ucbox1, 1, 1, 0, 0);	
		
		gc_a1ucbox2 = XCreateGC(display, windows,  GCFont,&values);
		set_color(display,red,gc_a1ucbox2);
		XSetLineAttributes(display, gc_a1ucbox2, 2, 0, 0, 0);
		
		gc_a2ucbox2 = XCreateGC(display, windows,  GCFont,&values);
		set_color(display,green,gc_a2ucbox2);
		XSetLineAttributes(display, gc_a2ucbox2, 2, 0, 0, 0);	
		
		gc_a3ucbox2 = XCreateGC(display, windows,  GCFont,&values);
		set_color(display,blue,gc_a3ucbox2);
		XSetLineAttributes(display, gc_a3ucbox2, 2, 0, 0, 0);	
	}
	void draw_ucbox(Display * display, Window & windows)
	{
		Eigen::Vector3d a000,a100,a010,a001,a111,a110,a101,a011;
		Eigen::Vector3d ra000,ra100,ra010,ra001,ra111,ra110,ra101,ra011;
		switch(draw_ucbox_type)
		{
			case 0:
			break;
			case 1:
			ra000 = t*corner;
			ra100 = t*(corner + a1);
			ra010 = t*(corner + a2);
			ra001 = t*(corner + a3);
			ra110 = t*(corner + a1 + a2);
			ra011 = t*(corner + a2 + a3);
			ra101 = t*(corner + a3 + a1);	
			ra111 = t*(corner + a1+a2+a3);
			

			XDrawLine(display,windows,gc_a1ucbox1,static_cast<int>(r* ra000.x() + ox),static_cast<int>(r* ra000.y() + oy),
				                              static_cast<int>(r* ra100.x() + ox),static_cast<int>(r* ra100.y() + oy));
			XDrawLine(display,windows,gc_a2ucbox1,static_cast<int>(r* ra000.x() + ox),static_cast<int>(r* ra000.y() + oy),
				                              static_cast<int>(r* ra010.x() + ox),static_cast<int>(r* ra010.y() + oy));	
			XDrawLine(display,windows,gc_a3ucbox1,static_cast<int>(r* ra000.x() + ox),static_cast<int>(r* ra000.y() + oy),
				                              static_cast<int>(r* ra001.x() + ox),static_cast<int>(r* ra001.y() + oy));	
							      
			XDrawLine(display,windows,gc_a2ucbox1,static_cast<int>(r* ra110.x() + ox),static_cast<int>(r* ra110.y() + oy),
				                              static_cast<int>(r* ra100.x() + ox),static_cast<int>(r* ra100.y() + oy));
			XDrawLine(display,windows,gc_a1ucbox1,static_cast<int>(r* ra110.x() + ox),static_cast<int>(r* ra110.y() + oy),
				                              static_cast<int>(r* ra010.x() + ox),static_cast<int>(r* ra010.y() + oy));	
			XDrawLine(display,windows,gc_a3ucbox1,static_cast<int>(r* ra110.x() + ox),static_cast<int>(r* ra110.y() + oy),
				                              static_cast<int>(r* ra111.x() + ox),static_cast<int>(r* ra111.y() + oy));	

			XDrawLine(display,windows,gc_a3ucbox1,static_cast<int>(r* ra101.x() + ox),static_cast<int>(r* ra101.y() + oy),
				                              static_cast<int>(r* ra100.x() + ox),static_cast<int>(r* ra100.y() + oy));
			XDrawLine(display,windows,gc_a2ucbox1,static_cast<int>(r* ra101.x() + ox),static_cast<int>(r* ra101.y() + oy),
				                              static_cast<int>(r* ra111.x() + ox),static_cast<int>(r* ra111.y() + oy));	
			XDrawLine(display,windows,gc_a1ucbox1,static_cast<int>(r* ra101.x() + ox),static_cast<int>(r* ra101.y() + oy),
				                              static_cast<int>(r* ra001.x() + ox),static_cast<int>(r* ra001.y() + oy));	
			
			XDrawLine(display,windows,gc_a1ucbox1,static_cast<int>(r* ra011.x() + ox),static_cast<int>(r* ra011.y() + oy),
				                              static_cast<int>(r* ra111.x() + ox),static_cast<int>(r* ra111.y() + oy));
			XDrawLine(display,windows,gc_a3ucbox1,static_cast<int>(r* ra011.x() + ox),static_cast<int>(r* ra011.y() + oy),
				                              static_cast<int>(r* ra010.x() + ox),static_cast<int>(r* ra010.y() + oy));	
			XDrawLine(display,windows,gc_a2ucbox1,static_cast<int>(r* ra011.x() + ox),static_cast<int>(r* ra011.y() + oy),
				                              static_cast<int>(r* ra001.x() + ox),static_cast<int>(r* ra001.y() + oy));								      
			
			break;
			case 2:
			ra000 = t*corner;
			ra100 = t*(corner + a1);
			ra010 = t*(corner + a2);
			ra001 = t*(corner + a3);
			ra110 = t*(corner + a1 + a2);
			ra011 = t*(corner + a2 + a3);
			ra101 = t*(corner + a3 + a1);	
			ra111 = t*(corner + a1+a2+a3);
			

			XDrawLine(display,windows,gc_a1ucbox2,static_cast<int>(r* ra000.x() + ox),static_cast<int>(r* ra000.y() + oy),
				                              static_cast<int>(r* ra100.x() + ox),static_cast<int>(r* ra100.y() + oy));
			XDrawLine(display,windows,gc_a2ucbox2,static_cast<int>(r* ra000.x() + ox),static_cast<int>(r* ra000.y() + oy),
				                              static_cast<int>(r* ra010.x() + ox),static_cast<int>(r* ra010.y() + oy));	
			XDrawLine(display,windows,gc_a3ucbox2,static_cast<int>(r* ra000.x() + ox),static_cast<int>(r* ra000.y() + oy),
				                              static_cast<int>(r* ra001.x() + ox),static_cast<int>(r* ra001.y() + oy));	
							      
			XDrawLine(display,windows,gc_a2ucbox2,static_cast<int>(r* ra110.x() + ox),static_cast<int>(r* ra110.y() + oy),
				                              static_cast<int>(r* ra100.x() + ox),static_cast<int>(r* ra100.y() + oy));
			XDrawLine(display,windows,gc_a1ucbox2,static_cast<int>(r* ra110.x() + ox),static_cast<int>(r* ra110.y() + oy),
				                              static_cast<int>(r* ra010.x() + ox),static_cast<int>(r* ra010.y() + oy));	
			XDrawLine(display,windows,gc_a3ucbox2,static_cast<int>(r* ra110.x() + ox),static_cast<int>(r* ra110.y() + oy),
				                              static_cast<int>(r* ra111.x() + ox),static_cast<int>(r* ra111.y() + oy));	

			XDrawLine(display,windows,gc_a3ucbox2,static_cast<int>(r* ra101.x() + ox),static_cast<int>(r* ra101.y() + oy),
				                              static_cast<int>(r* ra100.x() + ox),static_cast<int>(r* ra100.y() + oy));
			XDrawLine(display,windows,gc_a2ucbox2,static_cast<int>(r* ra101.x() + ox),static_cast<int>(r* ra101.y() + oy),
				                              static_cast<int>(r* ra111.x() + ox),static_cast<int>(r* ra111.y() + oy));	
			XDrawLine(display,windows,gc_a1ucbox2,static_cast<int>(r* ra101.x() + ox),static_cast<int>(r* ra101.y() + oy),
				                              static_cast<int>(r* ra001.x() + ox),static_cast<int>(r* ra001.y() + oy));	
			
			XDrawLine(display,windows,gc_a1ucbox2,static_cast<int>(r* ra011.x() + ox),static_cast<int>(r* ra011.y() + oy),
				                              static_cast<int>(r* ra111.x() + ox),static_cast<int>(r* ra111.y() + oy));
			XDrawLine(display,windows,gc_a3ucbox2,static_cast<int>(r* ra011.x() + ox),static_cast<int>(r* ra011.y() + oy),
				                              static_cast<int>(r* ra010.x() + ox),static_cast<int>(r* ra010.y() + oy));	
			XDrawLine(display,windows,gc_a2ucbox2,static_cast<int>(r* ra011.x() + ox),static_cast<int>(r* ra011.y() + oy),
				                              static_cast<int>(r* ra001.x() + ox),static_cast<int>(r* ra001.y() + oy));      

			break;
			default: ;
		}
	  
	}
	// end ucbox //


	// center //
	int draw_center_type;
	void set_draw_center_type() {     draw_center_type = (draw_center_type+1) % 3; }
	GC gc_center;
	Eigen::Vector3d center;	
	void init_draw_center(Display * display, Window & windows)
	{
		gc_center = XCreateGC(display, windows, 0, 0);
		set_color(display,"#33CCFF",gc_center);
		XSetLineAttributes(display, gc_center, 1, 1, 0, 0);
	}
	void draw_center(Display * display, Window & windows)
	{
		switch(draw_center_type)
		{
			case 0:
			break;
			case 1:
			break;
			case 2:
			break;
			default: ;
		}
	}
	void set_center()
	{
		switch(draw_center_type)
		{
			case 0: center = center_geom;
			break;
			case 1: center = (a1+a2+a3)/2.0+corner;
			break;
			case 2: center << 0,0,0;
			break;
			default: ;
		}
		tra = Eigen::Translation3d(-center);
		did_view_transformed = false;
	}	
	// end center //

	void set_view()
	{

		//std::cerr<< bbox << std::endl;
		if( (bbox.x() <= bbox.y()) && (bbox.x() <= bbox.z())) setangley(1.57);
		if( (bbox.y() <= bbox.x()) && (bbox.y() <= bbox.z())) setanglex(1.57);
		if( (bbox.z() <= bbox.y()) && (bbox.z() <= bbox.x())) setanglez(1.57);
		
		if (bbox.x() < bbox.z()) std::swap(bbox.x(),bbox.z());
		if (bbox.y() < bbox.z()) std::swap(bbox.y(),bbox.z());
		if (bbox.x() < bbox.y()) std::swap(bbox.x(),bbox.y());
		
		
		// better algorithm needed...
		if( (r*bbox.x() < 400)&&(r*bbox.y() < 400) ) r = 2*r; 
		if( (r*bbox.x() > 900)&&(r*bbox.y() > 600) ) r = r/2; 
		
		width = (int)(1.5*r*bbox.x()) + 50;
		height = (int)(1.5*r*bbox.y())+ 50;
		
		ox = width/2;
		oy = height/2;

		
	}

	////  coord settings /////
	Eigen::Vector3d bboxmin,bboxmax,bbox;
	Eigen::Vector3d corner;
	Eigen::Vector3d center_geom;
	Eigen::Vector3d a1,a2,a3,na1,na2,na3;	
	std::vector<Eigen::Vector3d> coords_uc;
	std::vector<std::pair<int,int>> bond_topology;
	void coordinit(bool erase_selection = true,bool recalculate_topology = true,bool erase_measures = true)
	{
		did_view_transformed = false; 
		
		rotated_coords = coords;  
		coords_uc = coords;
		coordX.resize(n);
		coordY.resize(n);
		
//		if(erase_selection)
//		{
//        		selected_atom.resize(n);
//	        	for(int i=0; i< n ; i++) selected_atom[i] = 0;
//	        }
		
		a1 = lattice[0];
		a2 = lattice[1];
		a3 = lattice[2];
        
		if(a1.norm() * a2.norm() * a3.norm() > 0.001)
		{
			na1 = a1.normalized();
			na2 = a2.normalized();
			na3 = a3.normalized();
		}
		else 
		{
			a1 << 1,0,0;
			a2 << 0,1,0;
			a3 << 0,0,1;
			na1 = a1;
			na2 = a2;
			na3 = a3;
			
		}
		
		for(int i=0; i<n; i++)
		{
			coords_uc[i].x() = na1.dot(coords[i]);
			coords_uc[i].y() = na2.dot(coords[i]);
			coords_uc[i].z() = na3.dot(coords[i]);
		}
		
		Eigen::Vector3d corner_uc = coords_uc[0];
		for(int i=0; i<n; i++)
		{
			if(coords_uc[i].x() < corner_uc.x()) corner_uc.x() = coords_uc[i].x();
			if(coords_uc[i].y() < corner_uc.y()) corner_uc.y() = coords_uc[i].y();
			if(coords_uc[i].z() < corner_uc.z()) corner_uc.z() = coords_uc[i].z();
		}
		
		corner = corner_uc.x()*na1 + corner_uc.y()*na2 + corner_uc.z()*na3;

		center_geom << 0,0,0;
		for(int i=0; i<n; i++) center_geom += coords[i];
		center_geom /= double(n);
		
		bboxmin = coords[0];
		bboxmax = coords[0];
		for(int i=0; i<n; i++)
		{
			if(coords[i].x() < bboxmin.x()) bboxmin.x() = coords[i].x();
			if(coords[i].y() < bboxmin.y()) bboxmin.y() = coords[i].y();
			if(coords[i].z() < bboxmin.z()) bboxmin.z() = coords[i].z();
			if(coords[i].x() > bboxmax.x()) bboxmax.x() = coords[i].x();
			if(coords[i].y() > bboxmax.y()) bboxmax.y() = coords[i].y();
			if(coords[i].z() > bboxmax.z()) bboxmax.z() = coords[i].z();
		}
		
		bbox = bboxmax-bboxmin;

		if(erase_selection)
		{
        		selected_atom.resize(n);
	        	for(int i=0; i< n ; i++) selected_atom[i] = 0;
	        }
            
                if(erase_measures)
                {
        		connections.clear();
        		connecting_atom = -1;
                }
            
	        if(recalculate_topology)
	        {	
        		bond_topology.clear();
	        	for(int i = 0; i < n; i++)
		        for(int j = i; j < n; j++)
        		if(j != i)
	        	{	
		        	Eigen::Vector3d &ci = rotated_coords[i];
			        Eigen::Vector3d &cj = rotated_coords[j];
			
        			if( (ci-cj).norm() < av.radius[labels[i]]+av.radius[labels[j]] + dist )
	        		bond_topology.push_back(std::pair<int,int>(i,j));
		        }
		}

	}
	////  end coord settings /////



	void drawinit(Display * display, Window & windows,atomview & v)
	{
		av = v;
		rot = Eigen::AngleAxisd(0.0, Eigen::Vector3d(1,0,0));
		tra = Eigen::Translation3d(Eigen::Vector3d(0,0,0));
		
		draw_center_type = 0;
		set_center();
		init_draw_center(display,windows);
		
		draw_axis_type = 0;
		set_axis_length();
		init_draw_axis(display,windows);
		
		draw_bond_type = 2;
		init_draw_bond(display,windows);
		
		draw_atom_type = 0;
		init_draw_atom(display,windows); 
		
		draw_label_type = 0;
		init_draw_label(display,windows); 		

		draw_measure_type = 0;
		init_draw_measure(display,windows); 		
		
		draw_help_type = 1;
		init_draw_help(display,windows); 			
	
		draw_ucbox_type = 0;
		init_draw_ucbox(display,windows);
		
		draw_selatom_type = 1;
		init_draw_selatom(display,windows); 		
		
	}

	void draw(Display * display, Window & windows)
	{
		t = rot*tra;
		draw_center(display,windows);
		draw_ucbox(display,windows);
		draw_axis(display,windows);
		draw_bond(display,windows);
		draw_atom(display,windows);
		draw_label(display,windows);
		draw_measure(display,windows);
		draw_help(display,windows);
		draw_selatom(display,windows);
	}
	

};


static time_t last_time;
bool watch_file_modify(const char * file)
{
    struct stat fileinfo; 
	    if (stat(file, &fileinfo)) return false; 
	    if(last_time != fileinfo.st_mtime) 
	    {
		   last_time = fileinfo.st_mtime;
		   return true;
	    }
      return false;
} 


void view(std::string fn)
{
	xyzview c;
	load(fn,c);
        
	c.coordinit();
	c.set_view();
	atomview av;
	
	Display *display;
	Window root, window;
	long fgcolor, bgcolor;
	int screen;
	int eventmask = KeyPressMask|ExposureMask|ButtonPressMask|Button1MotionMask|Button2MotionMask|Button3MotionMask|Button4MotionMask|Button5MotionMask;
	XEvent event;
	XGCValues gcval;
	GC draw;
	
	if (!(display = XOpenDisplay(NULL))) throw std::runtime_error("Cannot open display.");

	root = RootWindow(display,screen = DefaultScreen(display));
	bgcolor = BlackPixel(display,screen);
	fgcolor = WhitePixel(display,screen);

	window = XCreateSimpleWindow(display,root,50,50,c.width,c.height,2,fgcolor,bgcolor);
	
	XSelectInput(display,window,eventmask);
	XMapWindow(display,window);
	XMapRaised(display, window);


	int px;
	int py;
	
	int prpx;
	int prpy;
	
	int sox;
	int soy;
	
	c.drawinit(display,window,av);
	
	
	int x11_fd;
	fd_set in_fds;
	struct timeval tv;
	x11_fd = ConnectionNumber(display);
	tv.tv_sec = 0;
	tv.tv_usec = 0;

        double dangle=0.1;
        int danglestep=2;
	for (;;) 
	{
	  
		FD_ZERO(&in_fds);
		FD_SET(x11_fd, &in_fds);

		// Wait for X Event or a Timer
		int res = select(x11_fd+1,&in_fds, NULL, NULL, &tv);
		if (res == -1) throw std::runtime_error("Error in select");
		else if (res == 0 )
		{
			if(watch_file_modify(fn.c_str()))
			{
				load(fn,c);
				c.coordinit(); 
				XClearWindow(display,window);c.draw(display,window);
			}
			tv.tv_sec = 0;	tv.tv_usec = 200000;  // 200000us = 200ms = 0.2s 
		}
		else if(watch_file_modify(fn.c_str()))   { load(fn,c); c.coordinit() ; XClearWindow(display,window);c.draw(display,window); }
		
		
		//XWindowEvent(display,window,eventmask,&event);
		while(XPending(display)) { XNextEvent(display,&event);
		
//		if(watch_file_modify(fn.c_str()))   { load(fn,c); c.coordinit() ; XClearWindow(display,window);c.draw(display,window); }
		switch (event.type) 
		{

			case Expose:
			XClearWindow(display,window);
			c.draw(display,window);
			break;
			case MotionNotify:
			if (event.xmotion.state & Button1Mask) 
			{
				px = event.xmotion.x;
				py = event.xmotion.y;
				bool change = false;

				if(px < prpx-danglestep) { c.rotatey(dangle);  change = true; }
				if(px > prpx+danglestep) { c.rotatey(-dangle); change = true; }
				if(py < prpy-danglestep) { c.rotatex(-dangle); change = true; }
				if(py > prpy+danglestep) { c.rotatex(dangle);  change = true; }
				
				
				if(change) 
				{	
                                        if(dangle < 0.1) dangle+=0.01;
                                        if(dangle > 0.05) danglestep=2;
					XClearWindow(display,window);
					c.draw(display,window);
					prpx = px;
					prpy = py;
				}
				
				

				
			} else if (event.xmotion.state & Button3Mask) 
			{
				px = event.xmotion.x;
				py = event.xmotion.y;
				bool change = false;
				if(px < prpx-3) { c.translatex((-prpx+px));  change = true; }
				if(px > prpx+3) { c.translatex((-prpx+px));  change = true; }
				if(py < prpy-3) { c.translatey((-prpy+py));  change = true; }
				if(py > prpy+3) { c.translatey((-prpy+py));  change = true; }
				
				if(change) 
				{
					XClearWindow(display,window);
					c.draw(display,window);
					prpx = px;
					prpy = py;
				}
			  
			}
			break;
			case ButtonPress:
			if (event.xbutton.button == Button1)
			{
				prpx = event.xbutton.x;
				prpy = event.xbutton.y;
                                
                                dangle = 0.01;
                                danglestep=0;
                                
				if(c.draw_selatom_type != 0) 
				{
				     c.select_atom(prpx,prpy);
				     c.draw(display,window);
				}
			}
			if (event.xbutton.button == Button2)
			{
				
				prpx = event.xbutton.x;
				prpy = event.xbutton.y;
				if(c.draw_selatom_type != 0) 
				{
				     c.deselect_allatom();
				     XClearWindow(display,window);
				     c.draw(display,window);
				}
			}			
			if (event.xbutton.button == Button3)
			{
				prpx = event.xbutton.x;
				prpy = event.xbutton.y;
				if(c.draw_selatom_type != 0) 
				{
				     c.deselect_atom(prpx,prpy);
				     XClearWindow(display,window);
				     c.draw(display,window);
				}				
			}			
			if (event.xbutton.button == Button5)
			{
				c.scale(5);
				XClearWindow(display,window);
				c.draw(display,window);
			}
			if (event.xbutton.button == Button4)
			{
				c.scale(-5);
				XClearWindow(display,window);
				c.draw(display,window);
			}
			
			
			//if (event.xbutton.button == Button3) exit(0);
			break;
			case KeyPress:
			char sym; sym = XLookupKeysym(&event.xkey, 0);
			if (sym == 'q') { XDestroyWindow(display, window); exit(0); }
			
			//std::cerr << sym << ":" << XLookupKeysym(&event.xkey, 0) << std::endl;
			if (sym == 'h')  { c.set_draw_help_type(); XClearWindow(display,window);c.draw(display,window); }
			if (sym == 'b')  { c.set_draw_bond_type(); XClearWindow(display,window); c.draw(display,window); }
			if (sym == 'a')  { c.set_draw_atom_type(); XClearWindow(display,window);c.draw(display,window); }
			if (sym == 'c')  { c.set_draw_axis_type(); XClearWindow(display,window);c.draw(display,window); }
			if (sym == 'l')  { c.set_draw_label_type(); XClearWindow(display,window);c.draw(display,window); }
			if (sym == 'u')  { c.set_draw_ucbox_type(); XClearWindow(display,window);c.draw(display,window); }
			if (sym == '1')  {  c.draw_help_type = 1; c.draw_bond_type = 2; c.draw_atom_type = 0; 
				            c.draw_axis_type = 0; c.draw_label_type = 0; c.draw_ucbox_type = 0; 
				            XClearWindow(display,window); c.draw(display,window); }
			if (sym == '2')  {  c.draw_help_type = 1; c.draw_bond_type = 2; c.draw_atom_type = 2; 
				            c.draw_axis_type = 1; c.draw_label_type = 0; c.draw_ucbox_type = 0; 
				            XClearWindow(display,window); c.draw(display,window); }	
			if (sym == '3')  {  c.draw_help_type = 1; c.draw_bond_type = 2; c.draw_atom_type = 1; 
				            c.draw_axis_type = 1; c.draw_label_type = 0; c.draw_ucbox_type = 1; 
				            XClearWindow(display,window); c.draw(display,window); }	
			if (sym == '4')  {  c.draw_help_type = 1; c.draw_bond_type = 2; c.draw_atom_type = 1; 
				            c.draw_axis_type = 1; c.draw_label_type = 1; c.draw_ucbox_type = 1; 
				            XClearWindow(display,window); c.draw(display,window); }
			if (sym == 'x')  { c.setanglex(1.57); XClearWindow(display,window);c.draw(display,window); }    
			if (sym == 'y')  { c.setangley(1.57); XClearWindow(display,window);c.draw(display,window); }    
			if (sym == 'z')  { c.setanglez(1.57); XClearWindow(display,window);c.draw(display,window); }
			if (sym == 'o')  { c.set_draw_center_type(); c.set_center(); XClearWindow(display,window);c.draw(display,window); }
			if (sym == 's')  { c.set_draw_selatom_type(); XClearWindow(display,window);c.draw(display,window); }	
			if (sym == 'm')  { c.set_draw_measure_type(); XClearWindow(display,window);c.draw(display,window); }	
			break;
			default: ;
		}     } /* while loop*/
	}
}


struct coord_frames : std::vector<xyz> 
{
    int frame_index;
    int index() const
    { return frame_index; }
    void set_index(int ind,xyzview & c)
    {
        if(ind >= size()) ind = size()-1;
        frame_index =  ind;
        set(c);
    }
    void get_init(xyzview & c) 
    {
        frame_index = 0;
        set(c);
    } 
    
    void get_forward(xyzview & c) 
    {
        if(frame_index < size()-1) 
        {
            frame_index++;
            set(c);
        }
    } 
    void get_backward(xyzview & c) 
    {
        if(0<frame_index) 
        {
            frame_index--;
            set(c);
        }
        
    } 
    void get_begin(xyzview & c) 
    {
        if(frame_index != 0)
        {
            frame_index = 0;
            set(c);
        }
    } 
    void get_end(xyzview & c) 
    {
        if(frame_index != size()-1)
        {
            frame_index = size()-1;
            set(c);
        }
    } 
    
    void set(xyzview & c)
    {
        c.n = (*this)[frame_index].n;
        bool issamestructure = (c.labels == (*this)[frame_index].labels);
        //if(issamestructure) ;
        c.labels = (*this)[frame_index].labels;
        c.lattice = (*this)[frame_index].lattice;
        c.coords = (*this)[frame_index].coords;
        c.comment = (*this)[frame_index].comment;
        c.selected = (*this)[frame_index].selected;
        std::string st;
        util::to(frame_index+1,c.frame_label);
        util::to(size(),st);
        c.frame_label+="/"+st;
        c.coordinit(!issamestructure,true,!issamestructure);
        c.is_edit_mode = false;
    }
    
    void write(const xyzview & c)
    {
        (*this)[frame_index].coords = c.coords; // has to be more complete

    }

    void insert_edit(xyzview & c)
    {
        
        xyz cc = (*this)[frame_index];
        cc.coords = c.coords; //has to be more complete
        insert(begin()+frame_index+1,cc);
        frame_index++;
        std::string st;
        util::to(frame_index+1,c.frame_label);
        util::to(size(),st);
        c.frame_label+="/"+st;
        //c.coordinit(!issamestructure,true,!issamestructure);

    }

    void insert_edit_remove_selected(xyzview & c)
    {
        
        xyz cc = (*this)[frame_index];
        cc.coords = c.coords; //has to be more complete
        insert(begin()+frame_index+1,cc);
        frame_index++;
        std::string st;
        util::to(frame_index+1,c.frame_label);
        util::to(size(),st);
        c.frame_label+="/"+st;
        //c.coordinit(!issamestructure,true,!issamestructure);

    }

    void erase_edit(xyzview & c)
    {
        if(size()>1)
        {        

            if(0<frame_index) 
            {
                frame_index--;
                erase(begin()+frame_index+1);
                set(c);
            }

    
        }

    }
    
};

void view_ani(std::string fn)
{
        coord_frames cf;
        load(fn,cf);

        xyzview c;
        cf.get_init(c);
        
	c.set_view();
	atomview av;
	
	Display *display;
	Window root, window;
	long fgcolor, bgcolor;
	int screen;
	int eventmask = KeyPressMask|ExposureMask|ButtonPressMask|Button1MotionMask|Button2MotionMask|Button3MotionMask|Button4MotionMask|Button5MotionMask;
	XEvent event;
	XGCValues gcval;
	GC draw;
	
	if (!(display = XOpenDisplay(NULL))) throw std::runtime_error("Cannot open display.");

	root = RootWindow(display,screen = DefaultScreen(display));
	bgcolor = BlackPixel(display,screen);
	fgcolor = WhitePixel(display,screen);

	window = XCreateSimpleWindow(display,root,50,50,c.width,c.height,2,fgcolor,bgcolor);
	
	XSelectInput(display,window,eventmask);
	XMapWindow(display,window);
	XMapRaised(display, window);


	int px;
	int py;
	
	int prpx;
	int prpy;
	
	int sox;
	int soy;
	
	c.drawinit(display,window,av);
	
        double dangle=0.1;
        int danglestep=2;
	for (;;) 
	{
		//XWindowEvent(display,window,eventmask,&event);
		while(XPending(display)) { XNextEvent(display,&event);
		
		switch (event.type) 
		{

			case Expose:
			XClearWindow(display,window);
			c.draw(display,window);
			break;
			case MotionNotify:
			if (event.xmotion.state & Button1Mask) 
			{
				px = event.xmotion.x;
				py = event.xmotion.y;
				bool change = false;

				if(px < prpx-danglestep) { c.rotatey(dangle);  change = true; }
				if(px > prpx+danglestep) { c.rotatey(-dangle); change = true; }
				if(py < prpy-danglestep) { c.rotatex(-dangle); change = true; }
				if(py > prpy+danglestep) { c.rotatex(dangle);  change = true; }
				
				
				if(change) 
				{	
                                        if(dangle < 0.1) dangle+=0.01;
                                        if(dangle > 0.05) danglestep=2;
					XClearWindow(display,window);
					c.draw(display,window);
					prpx = px;
					prpy = py;
				}
				
				

				
			} else if (event.xmotion.state & Button3Mask) 
			{
				px = event.xmotion.x;
				py = event.xmotion.y;
				bool change = false;
				if(px < prpx-3) { c.translatex((-prpx+px));  change = true; }
				if(px > prpx+3) { c.translatex((-prpx+px));  change = true; }
				if(py < prpy-3) { c.translatey((-prpy+py));  change = true; }
				if(py > prpy+3) { c.translatey((-prpy+py));  change = true; }
				
				if(change) 
				{
					XClearWindow(display,window);
					c.draw(display,window);
					prpx = px;
					prpy = py;
				}
			  
			}
			break;
			case ButtonPress:
			if (event.xbutton.button == Button1)
			{
				prpx = event.xbutton.x;
				prpy = event.xbutton.y;
                                
                                dangle = 0.01;
                                danglestep=0;
                                
				if(c.draw_selatom_type != 0) 
				{
				     c.select_atom(prpx,prpy);
				     c.draw(display,window);
				}
			}
			if (event.xbutton.button == Button2)
			{
				
				prpx = event.xbutton.x;
				prpy = event.xbutton.y;
                                c.connect_atom(prpx,prpy);
			        XClearWindow(display,window);
			        c.draw(display,window);
			}			
			if (event.xbutton.button == Button3)
			{
				prpx = event.xbutton.x;
				prpy = event.xbutton.y;
				if(c.draw_selatom_type != 0) 
				{
				     c.deselect_atom(prpx,prpy);
				     XClearWindow(display,window);
				     c.draw(display,window);
				}
			}			
			if (event.xbutton.button == Button5)
			{
				c.scale(5);
				XClearWindow(display,window);
				c.draw(display,window);
			}
			if (event.xbutton.button == Button4)
			{
				c.scale(-5);
				XClearWindow(display,window);
				c.draw(display,window);
			}
			
			
			//if (event.xbutton.button == Button3) exit(0);
			break;
			case KeyPress:
			KeySym keysym; keysym = XLookupKeysym(&event.xkey, 0);
			char sym; //sym = XLookupKeysym(&event.xkey, 0);
			sym = keysym;
			
			
			if (sym == 'q') { XDestroyWindow(display, window); exit(0); }
			if (sym == 'e') { c.is_edit_mode = true; XClearWindow(display,window); c.draw(display,window); }			

			if(c.is_edit_mode)
			{
                        if (sym == 'u')  { c.edit_translate_x(+0.1); c.coordinit(false,true,false); XClearWindow(display,window); c.draw(display,window); }			
                        if (sym == 'h')  { c.edit_translate_x(-0.1); c.coordinit(false,true,false); XClearWindow(display,window); c.draw(display,window); }			
                        if (sym == 'i')  { c.edit_translate_y(+0.1); c.coordinit(false,true,false); XClearWindow(display,window); c.draw(display,window); }			
                        if (sym == 'j')  { c.edit_translate_y(-0.1); c.coordinit(false,true,false); XClearWindow(display,window); c.draw(display,window); }			
                        if (sym == 'o')  { c.edit_translate_z(+0.1); c.coordinit(false,true,false); XClearWindow(display,window); c.draw(display,window); }			
                        if (sym == 'k')  { c.edit_translate_z(-0.1); c.coordinit(false,true,false); XClearWindow(display,window); c.draw(display,window); }			
                        if (sym == 's')  { c.edit_send_away(); c.coordinit(false,true,false); XClearWindow(display,window); c.draw(display,window); }			

			if (sym == 'd') { cf.erase_edit(c); save(fn,cf); c.is_edit_mode = false; XClearWindow(display,window); c.draw(display,window); }			
			if (sym == 'a') { cf.insert_edit(c); save(fn,cf); XClearWindow(display,window); c.draw(display,window); }			
			if (sym == 'w') { cf.write(c); save(fn,cf); XClearWindow(display,window); c.draw(display,window); }			
			if (sym == 'v') { c.is_edit_mode = false; XClearWindow(display,window); c.draw(display,window); }			
			}
			else
			{
			if (sym == 'h')  { c.set_draw_help_type(); XClearWindow(display,window);c.draw(display,window); }
			//std::cerr << sym << ":" << XLookupKeysym(&event.xkey, 0) << std::endl;
			if (sym == 'b')  { c.set_draw_bond_type(); XClearWindow(display,window); c.draw(display,window); }
			if (sym == 'a')  { c.set_draw_atom_type(); XClearWindow(display,window);c.draw(display,window); }
			if (sym == 'c')  { c.set_draw_axis_type(); XClearWindow(display,window);c.draw(display,window); }
			if (sym == 'l')  { c.set_draw_label_type(); XClearWindow(display,window);c.draw(display,window); }
			if (sym == 'u')  { c.set_draw_ucbox_type(); XClearWindow(display,window);c.draw(display,window); }
			if (sym == '1')  {  c.draw_help_type = 1; c.draw_bond_type = 2; c.draw_atom_type = 0; 
				            c.draw_axis_type = 0; c.draw_label_type = 0; c.draw_ucbox_type = 0; 
				            XClearWindow(display,window); c.draw(display,window); }
			if (sym == '2')  {  c.draw_help_type = 1; c.draw_bond_type = 2; c.draw_atom_type = 2; 
				            c.draw_axis_type = 1; c.draw_label_type = 0; c.draw_ucbox_type = 0; 
				            XClearWindow(display,window); c.draw(display,window); }	
			if (sym == '3')  {  c.draw_help_type = 1; c.draw_bond_type = 2; c.draw_atom_type = 1; 
				            c.draw_axis_type = 1; c.draw_label_type = 0; c.draw_ucbox_type = 1; 
				            XClearWindow(display,window); c.draw(display,window); }	
			if (sym == '4')  {  c.draw_help_type = 1; c.draw_bond_type = 2; c.draw_atom_type = 1; 
				            c.draw_axis_type = 1; c.draw_label_type = 1; c.draw_ucbox_type = 1; 
				            XClearWindow(display,window); c.draw(display,window); }
			if (sym == 'x')  { c.setanglex(1.57); XClearWindow(display,window);c.draw(display,window); }    
			if (sym == 'y')  { c.setangley(1.57); XClearWindow(display,window);c.draw(display,window); }    
			if (sym == 'z')  { c.setanglez(1.57); XClearWindow(display,window);c.draw(display,window); }
			if (sym == 'o')  { c.set_draw_center_type(); c.set_center(); XClearWindow(display,window);c.draw(display,window); }
			if (sym == 's')  { c.set_draw_selatom_type(); XClearWindow(display,window);c.draw(display,window); }	
			if (sym == 'm')  { c.set_draw_measure_type(); XClearWindow(display,window);c.draw(display,window); }	
			if (sym == 'r')  { coord_frames cfnew; load(fn,cfnew); int fi = cf.index(); 
			                   cf = cfnew; 
			                   cf.get_init(c); 
			                   cf.set_index(fi,c);
			                   XClearWindow(display,window);c.draw(display,window); }
			}

			if (keysym == XK_Page_Up)  { cf.get_backward(c) ; XClearWindow(display,window);c.draw(display,window); }	
			if (keysym == XK_Page_Down)  { cf.get_forward(c) ; XClearWindow(display,window);c.draw(display,window); }	
			if (keysym == XK_Home)  { cf.get_begin(c) ; XClearWindow(display,window);c.draw(display,window); }	
			if (keysym == XK_End)  { cf.get_end(c) ; XClearWindow(display,window);c.draw(display,window); }	
                        
			break;
			default: ;
		}     } /* while loop*/
	}
}



int main(int argc, char** argv)
{
try
{   
	cmd::arguments arg(argc,argv);
	cmd::switcharg<false> help(arg,"-h","--help", "print help message");
	cmd::switcharg<false> watch(arg,"-W","--Watch", "Watch xyz file (Does not work for animation)");
	cmd::posarg<std::string> xyzfn(arg,"input file name", "");
        
	if(*help)
	{
		arg.print_help(std::cout,"xyzview");
                std::cout << std::endl;
                std::cout << "Version 0.91b"<< std::endl;
                std::cout << "Copyright (c) 2010 David Zsolt Manrique (david.zsolt.manrique@gmail.com)"<< std::endl;
    		return EXIT_SUCCESS;
	}
	
        if(*watch) view(*xyzfn); else view_ani(*xyzfn);

        ////////////////////////////////////////////////////
        
} catch(const char* message)
{
	std::cerr << message << std::endl;
	std::cerr << "(exit)" << std::endl;
	return EXIT_FAILURE;
} 
catch(const std::exception & e)
{
        std::cerr << e.what() << std::endl;
        std::cerr << "(exit)" << std::endl;
        return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
